using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using TTDotNet.Util;
/*
namespace TTDotNet.Engine.ThreeDEngine
{
    public class AJGrid : AJObject
    {
        string road_Straight = "../../artwork/512/BorderHighlight.png";
        //string road_Straight = "../../artwork/512/Road.jpg";
        Texture roadTex;

        #region GlobalVariables
        private List<CustomVertex.PositionTextured[]> gridVerts;

        private bool[,] addedIndices;

        private List<List<List<Tile>>> indexMap;
        private List<Dictionary<Texture, int[]>> numIndices;

        public Coordinate activeTile;
        private bool[] updateSet;
        
        private List<int[]> gridIndices;
        private bool updateBuffers;

        private int[] allIndices;
        private int indicesIn;

        private int width;
        private int length;
        private int strips;

        private VertexBuffer[] vb;
        private IndexBuffer[] sib;

        private List<float[,]> texCoordsU;
        private List<float[,]> texCoordsV;
        private List<float[,]> texCoordsUF;
        private List<float[,]> texCoordsVF;

        #endregion

        #region Constructor
        public AJGrid(int width, int length)
        {
            SetupGrid(width, length);
        } 
        #endregion

        public void SetupGrid(int width, int length)
        {
            this.width = width;
            this.length = length;

            strips = (1);

            sib = new IndexBuffer[strips];

            gridVerts = new List<CustomVertex.PositionTextured[]>();
            updateSet = new bool[strips];

            indexMap = new List<List<List<Tile>>>();

            for (int s = 0; s < strips; s++)
            {
                List<List<Tile>> temp = new List<List<Tile>>();

                indexMap.Add(temp);

                for (int p = 0; p < 8; p++)
                {
                    List<Tile> temp2 = new List<Tile>();
                    indexMap[s].Add(temp2);
                }
            }

            addedIndices = new bool[width, length];

            activeTile = new Coordinate();

            gridIndices = new List<int[]>(strips);

            for (int s = 0; s < strips; s++)
            {
                gridIndices.Add(new int[(width * length * 6) / strips]);
            }

            allIndices = new int[width * length * 6];
            indicesIn = 0;

            numIndices = new List<Dictionary<Texture, int[]>>();
            vb = new VertexBuffer[8];

            setupEvenEven();
            setupOddEven();

            for (int z = 0; z < 8; z++)
            {
                int count = 0;
                CustomVertex.PositionTextured[] dirVerts = new CustomVertex.PositionTextured[(width + 1) * (length + 1)];


                for (int y = 0; y < length + 1; y++)
                {
                    for (int x = 0; x < width + 1; x++)
                    {
                        dirVerts[count] = new CustomVertex.PositionTextured(x - 0.5f, 0, y - 0.5f, 0, 0);

                        //Calc verts;

                        float[,] uFloat;
                        float[,] vFloat;

                        if (z < 4)
                        {
                            uFloat = texCoordsU[z];
                            vFloat = texCoordsV[z];
                        }
                        else
                        {
                            uFloat = texCoordsUF[z - 4];
                            vFloat = texCoordsVF[z - 4];
                        }
    
                        dirVerts[count].Tu = uFloat[x % 2, y % 2];
                        dirVerts[count].Tv = vFloat[x % 2, y % 2];

                        count++;
                    }
                }
                gridVerts.Add(dirVerts);
            }
        }

        public void UpdateTile(Tile tile)
        {
            //System.Windows.Forms.MessageBox.Show("Tile " + tile.GetCoord() + " is rotated to " + tile.getRotateType());

            int oldO = tile.getIndexInfo().oriented;
            int newO = GetOrientation(tile.GetCoord().GetX(), tile.GetCoord().GetZ(), (int)tile.getIndexInfo().GetRotateType());

            if (oldO != newO)
            {
                tile.getIndexInfo().oriented = newO;
                indexMap[tile.getIndexInfo().stripNum][oldO].Remove(tile);
                indexMap[tile.getIndexInfo().stripNum][newO].Add(tile);
            }
        }

        public override void ReloadResources()
        {
            //SetupGrid(width, length);
        }

        public void SetIndices(Tile tile)
        {
            IndexInfo ii = tile.getIndexInfo();

            foreach (int a in ii.GetIndices())
            {
                    allIndices[indicesIn++] = a;
            }

            int x = ii.GetCoord().GetX();
            int y = ii.GetCoord().GetZ();
            int rotnum = (int)ii.GetRotateType();
            int stripToGoIn = x % strips;

            int index1 = stripToGoIn;
            int index2 = GetOrientation(x,y,rotnum);
            
            // set
           

            ii.stripNum = index1;
            ii.oriented = index2;

            indexMap[index1][index2].Add(tile);
          
        }

        public void finaliseIB(Microsoft.DirectX.Direct3D.Device device, AJCamera camera)
        {
            roadTex = TextureLoader.FromFile(device, road_Straight, D3DX.Default, D3DX.Default, D3DX.Default, Usage.None, Format.Unknown, Pool.Default
                , (Filter)D3DX.Default, (Filter)D3DX.Default, 0);

            for (int s = 0; s < 8; s++)
            {

                vb[s] = new VertexBuffer(
                typeof(CustomVertex.PositionTextured),
                gridVerts[s].Length,
                device,
                Usage.WriteOnly,
                CustomVertex.PositionTextured.Format,
                Pool.Default
                );

                vb[s].SetData(gridVerts[s], 0, LockFlags.None);

            }

            for (int i = 0; i < strips; i++)
            {
                sib[i] = new IndexBuffer(typeof(int), (width * length * 6) / strips, device, Usage.Dynamic, Pool.Default);
            }

            ConstructIndexBuffers(device, camera);
        }

        public void ConstructIndexBuffers(Device device, AJCamera camera)
        {
            int[] counts = new int[strips];

            for (int i = 0; i < strips; i++)
            {
                gridIndices[i] = (int[])sib[i].Lock(0, 0);
            }

            for (int strip = 0; strip < strips; strip++)
            {
                int startpoint = 0;

                for (int o = 0; o < 8; o++)
                {
                    foreach (Tile tile in indexMap[strip][o])
                    {
                        tile.getIndexInfo().SetBufferLoc(startpoint);
                        startpoint = startpoint + tile.getIndexInfo().GetIndices().Length;

                        foreach (int i in tile.getIndexInfo().GetIndices())
                        {
                            gridIndices[strip][counts[strip]++] = i;
                        }
                    }
                }
            }

            for (int s = 0; s < strips; s++)
            {
                sib[s].Unlock();
            }

        }

        public override void Render(Device myDevice, AJCamera camera)
        {
            myDevice.RenderState.Lighting = false;
            myDevice.Transform.World = Matrix.Identity;
            myDevice.VertexFormat = CustomVertex.PositionTextured.Format;
            myDevice.RenderState.CullMode = Cull.Clockwise;

            myDevice.SetTextureStageState(0, TextureStageStates.TextureTransform, (int)TextureTransform.Count2);

            //Matrix matrix90;
            //Matrix matrix180;
            //Matrix matrix270;

           // matrix90 = Matrix.RotationZ(Geometry.DegreeToRadian(90));
            //matrix180 = Matrix.RotationZ(Geometry.DegreeToRadian(180));
            //matrix270 = Matrix.RotationZ(Geometry.DegreeToRadian(270));

            

            for (int s = 0; s < strips; s++)
            {
                myDevice.Indices = sib[s];

                for (int p = 0; p < 8; p++)
                {
                    myDevice.SetStreamSource(0, vb[p], 0);

                    foreach (Tile tile in indexMap[s][p])
                    {
                        myDevice.SetTexture(0, tile.GetTexture());
                        /*
                        if (tile.getRotateType() == RotateType.Ninety)
                        {
                            myDevice.Transform.Texture0 = matrix90;
                        }
                        else if (tile.getRotateType() == RotateType.OneEighty)
                        {
                            myDevice.Transform.Texture0 = matrix180;
                        }
                        else if (tile.getRotateType() == RotateType.TwoSeventy)
                        {
                            myDevice.Transform.Texture0 = matrix270;
                        }
                        else
                        {
                            //myDevice.Transform.Texture0 = new Matrix();
                        }
                        
                        myDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, (width + 1) * (length + 1),
                                                        tile.getIndexInfo().GetBufferLoc(), 2);
                    }
                }
            }

            myDevice.RenderState.Lighting = true;
            
        }

        public int GetOrientation(int x, int y, int rotnum)
        {
            if (x % 2 == 0)
            {
                if (y % 2 == 0)
                {
                    return rotnum;
                }
                else
                {
                    return ((rotnum + 2) % 4) + 4;
                }
            }
            else
            {
                if (y % 2 == 0)
                {
                    return (rotnum + 4);
                }
                else
                {
                    return (rotnum + 2) % 4;
                }
            }
            return 0;
        }

        #region TextureCoordinates
        public void setupEvenEven()
        {
            texCoordsU = new List<float[,]>();
            texCoordsV = new List<float[,]>();

            float[,] uCoords0 = new float[2, 2];
            float[,] vCoords0 = new float[2, 2];

            //000000000000000000000000000000000000
            uCoords0[0, 0] = 0;
            vCoords0[0, 0] = 1;

            uCoords0[0, 1] = 0;
            vCoords0[0, 1] = 0;

            uCoords0[1, 0] = 1;
            vCoords0[1, 0] = 1;

            uCoords0[1, 1] = 1;
            vCoords0[1, 1] = 0;

            texCoordsU.Add(uCoords0);
            texCoordsV.Add(vCoords0);

            //1111111111111111111111111111111111
            float[,] uCoords1 = new float[2, 2];
            float[,] vCoords1 = new float[2, 2];

            uCoords1[0, 0] = 1;
            vCoords1[0, 0] = 1;

            uCoords1[0, 1] = 0;
            vCoords1[0, 1] = 1;

            uCoords1[1, 0] = 1;
            vCoords1[1, 0] = 0;

            uCoords1[1, 1] = 0;
            vCoords1[1, 1] = 0;

            texCoordsU.Add(uCoords1);
            texCoordsV.Add(vCoords1);

            float[,] uCoords3 = new float[2, 2];
            float[,] vCoords3 = new float[2, 2];


            //2222222222222222222222222222222222
            float[,] uCoords2 = new float[2, 2];
            float[,] vCoords2 = new float[2, 2];


            uCoords2[0, 0] = 1;
            vCoords2[0, 0] = 0;

            uCoords2[0, 1] = 1;
            vCoords2[0, 1] = 1;

            uCoords2[1, 0] = 0;
            vCoords2[1, 0] = 0;

            uCoords2[1, 1] = 0;
            vCoords2[1, 1] = 1;

            texCoordsU.Add(uCoords2);
            texCoordsV.Add(vCoords2);

            //3333333333333333333333333333333333
            uCoords3[0, 0] = 0;
            vCoords3[0, 0] = 0;

            uCoords3[0, 1] = 1;
            vCoords3[0, 1] = 0;

            uCoords3[1, 0] = 0;
            vCoords3[1, 0] = 1;

            uCoords3[1, 1] = 1;
            vCoords3[1, 1] = 1;

            texCoordsU.Add(uCoords3);
            texCoordsV.Add(vCoords3);
        }

        public void setupOddEven()
        {
            texCoordsUF = new List<float[,]>();
            texCoordsVF = new List<float[,]>();

            float[,] uCoords0 = new float[2, 2];
            float[,] vCoords0 = new float[2, 2];

            //000000000000000000000000000000000000
            uCoords0[0, 0] = 1;
            vCoords0[0, 0] = 1;

            uCoords0[0, 1] = 1;
            vCoords0[0, 1] = 0;

            uCoords0[1, 0] = 0;
            vCoords0[1, 0] = 1;

            uCoords0[1, 1] = 0;
            vCoords0[1, 1] = 0;

            texCoordsUF.Add(uCoords0);
            texCoordsVF.Add(vCoords0);

            //1111111111111111111111111111111111
            float[,] uCoords1 = new float[2, 2];
            float[,] vCoords1 = new float[2, 2];

            uCoords1[0, 0] = 1;
            vCoords1[0, 0] = 0;

            uCoords1[0, 1] = 0;
            vCoords1[0, 1] = 0;

            uCoords1[1, 0] = 1;
            vCoords1[1, 0] = 1;

            uCoords1[1, 1] = 0;
            vCoords1[1, 1] = 1;

            texCoordsUF.Add(uCoords1);
            texCoordsVF.Add(vCoords1);

            float[,] uCoords3 = new float[2, 2];
            float[,] vCoords3 = new float[2, 2];


            //2222222222222222222222222222222222
            float[,] uCoords2 = new float[2, 2];
            float[,] vCoords2 = new float[2, 2];


            uCoords2[0, 0] = 0;
            vCoords2[0, 0] = 0;

            uCoords2[0, 1] = 0;
            vCoords2[0, 1] = 1;

            uCoords2[1, 0] = 1;
            vCoords2[1, 0] = 0;

            uCoords2[1, 1] = 1;
            vCoords2[1, 1] = 1;

            texCoordsUF.Add(uCoords2);
            texCoordsVF.Add(vCoords2);

            //3333333333333333333333333333333333
            uCoords3[0, 0] = 0;
            vCoords3[0, 0] = 1;

            uCoords3[0, 1] = 1;
            vCoords3[0, 1] = 1;

            uCoords3[1, 0] = 0;
            vCoords3[1, 0] = 0;

            uCoords3[1, 1] = 1;
            vCoords3[1, 1] = 0;

            texCoordsUF.Add(uCoords3);
            texCoordsVF.Add(vCoords3);
        } 
        #endregion

        #region Picking Tile
        public override bool Pick(Vector3 rayStart, Vector3 rayDirection, AJCamera camera, out IntersectInformation intInf)
        {
            activeTile.SetX(-1);
            activeTile.SetZ(-1);

            int final1, final2, final3, finali;
            final1 = 0;
            final2 = 0;
            final3 = 0;
            finali = 0;

            // Convert ray to model space
            Matrix World =
                Matrix.Scaling(myScaling) *
                Matrix.RotationYawPitchRoll(myRotation.Y, myRotation.X, myRotation.Z) *
                Matrix.Translation(myPosition);

            Matrix inverseWorld = Matrix.Invert(World);

            Vector3 localStart = Vector3.TransformCoordinate(rayStart, inverseWorld);
            Vector3 localDirection = Vector3.TransformNormal(rayDirection, inverseWorld);
            localDirection.Normalize();

            bool check = false;
            IntersectInformation result = new IntersectInformation();

            int count = 0;
            int tris = 0;

            for (int i = 0; i < allIndices.Length - 2; i = i + 3)
            {
                if (camera.IsInViewFrustum(gridVerts[0][allIndices[i]].X, 0, gridVerts[0][allIndices[i]].Z, 2.0f))
                {
                    
                    count++;

                    check =
                    Geometry.IntersectTri(new Vector3(gridVerts[0][allIndices[i]].X, gridVerts[0][allIndices[i]].Y, gridVerts[0][allIndices[i]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 1]].X, gridVerts[0][allIndices[i + 1]].Y, gridVerts[0][allIndices[i + 1]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 2]].X, gridVerts[0][allIndices[i + 2]].Y, gridVerts[0][allIndices[i + 2]].Z),
                                            localStart, localDirection, out result);
                    if (check)
                    {
                        finali = i;
                        break;
                    }
                }
                tris++;
            }
            int square = (int)finali / 3;

            activeTile.SetX((square / 2 % width));
            activeTile.SetZ(square / 2 / length);

            intInf = result;
            return check;
        } 
        #endregion

    

    public int PickSide(Vector3 rayStart, Vector3 rayDirection, AJCamera camera, out IntersectInformation intInf)
        {
            activeTile.SetX(-1);
            activeTile.SetZ(-1);

            int final1, final2, final3, finali;
            final1 = 0;
            final2 = 0;
            final3 = 0;
            finali = 0;

            // Convert ray to model space
            Matrix World =
                Matrix.Scaling(myScaling) *
                Matrix.RotationYawPitchRoll(myRotation.Y, myRotation.X, myRotation.Z) *
                Matrix.Translation(myPosition);

            Matrix inverseWorld = Matrix.Invert(World);

            Vector3 localStart = Vector3.TransformCoordinate(rayStart, inverseWorld);
            Vector3 localDirection = Vector3.TransformNormal(rayDirection, inverseWorld);
            localDirection.Normalize();

            bool check = false;
            bool tileFound = false;

            IntersectInformation result = new IntersectInformation();

            int total = 0;

            for (int i = 0; i < allIndices.Length - 2; i = i + 6)
            {
                total = 0;   

                if (camera.IsInViewFrustum(gridVerts[0][allIndices[i]].X, 0, gridVerts[0][allIndices[i]].Z, 2.0f))
                {
                    
                    check =
                    Geometry.IntersectTri(new Vector3(gridVerts[0][allIndices[i]].X, gridVerts[0][allIndices[i]].Y, gridVerts[0][allIndices[i]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 1]].X, gridVerts[0][allIndices[i + 1]].Y, gridVerts[0][allIndices[i + 1]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 4]].X, gridVerts[0][allIndices[i + 4]].Y, gridVerts[0][allIndices[i + 4]].Z),
                                            localStart, localDirection, out result);

                    if (check) { total++; tileFound = true; }
                     
                    
                    check =
                    Geometry.IntersectTri(new Vector3(gridVerts[0][allIndices[i+1]].X, gridVerts[0][allIndices[i+1]].Y, gridVerts[0][allIndices[i+1]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 4]].X, gridVerts[0][allIndices[i + 4]].Y, gridVerts[0][allIndices[i + 4]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 2]].X, gridVerts[0][allIndices[i + 2]].Y, gridVerts[0][allIndices[i + 2]].Z),
                                            localStart, localDirection, out result);

                    if (check) { total = total + 2; tileFound = true; }
                    
                    check =
                    Geometry.IntersectTri(new Vector3(gridVerts[0][allIndices[i + 4]].X, gridVerts[0][allIndices[i + 4]].Y, gridVerts[0][allIndices[i + 4]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 2]].X, gridVerts[0][allIndices[i + 2]].Y, gridVerts[0][allIndices[i + 2]].Z),
                                            new Vector3(gridVerts[0][allIndices[i]].X, gridVerts[0][allIndices[i]].Y, gridVerts[0][allIndices[i]].Z),
                                            localStart, localDirection, out result);

                    if (check) { total = total + 4; tileFound = true; }
                    
                    check =
                    Geometry.IntersectTri(new Vector3(gridVerts[0][allIndices[i + 2]].X, gridVerts[0][allIndices[i + 2]].Y, gridVerts[0][allIndices[i + 2]].Z),
                                            new Vector3(gridVerts[0][allIndices[i]].X, gridVerts[0][allIndices[i]].Y, gridVerts[0][allIndices[i]].Z),
                                            new Vector3(gridVerts[0][allIndices[i + 1]].X, gridVerts[0][allIndices[i + 1]].Y, gridVerts[0][allIndices[i + 1]].Z),
                                            localStart, localDirection, out result);

                    if (check) { total = total + 8; tileFound = true; }
                     

                    if (tileFound) { finali = i; break; }
                    
                }
            }
            int square = finali / 6;

            activeTile.SetX(square % width);
            activeTile.SetZ((int)Math.Floor((double)(square / length)));

            intInf = result;
            return total;
        } 

    }
}*/